﻿using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Net.Http;
using System.Reflection;
using System.Threading.Tasks;
using System.Transactions;
using ZFY.AspNetCore;
using ZFY.Core;
using ZFY.UnitOfWork;
using ZFY.UnitOfWork.Interface;

namespace ZFY.AspNetCore
{
    public class UOWActionFilter : IAsyncActionFilter
    {
        public UOWActionFilter()
        {

        }
        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            if (!(context.ActionDescriptor is ControllerActionDescriptor))
            {
                
                 await next();
            }

            var methodInfo = context.ActionDescriptor.GetMethodInfo();
            var unitOfWorkAttr = UnitOfWorkHelper.GetUnitOfWorkAttributeOrNull(methodInfo);

            if (unitOfWorkAttr?.IsDisabled == true)
            {
                await next();
                return;
            }

            var options = CreateOptions(context, unitOfWorkAttr);

            var unitOfWorkManager = context.HttpContext.RequestServices.GetRequiredService<IUnitOfWorkManager>();

            Console.Out.WriteLine(unitOfWorkManager.Current?.Id);
            Console.Out.WriteLine(unitOfWorkManager.Id);
            using (var uow = unitOfWorkManager.Begin(options))
            {
             
                var result = await next();

                //await uow.CompleteAsync(context.HttpContext.RequestAborted);
                if (Succeed(result))
                {
                    await uow.CompleteAsync(context.HttpContext.RequestAborted);
                }
                //else
                //{
                //    await uow.RollbackAsync(context.HttpContext.RequestAborted);
                //}
            }
        }


        private UnitOfWorkOption CreateOptions(ActionExecutingContext context, UnitOfWorkAttribute unitOfWorkAttribute)
        {
            var options = new UnitOfWorkOption();

            unitOfWorkAttribute?.SetOptions(options);

            if (unitOfWorkAttribute?.Scope == null)
            {
                options.Scope = !string.Equals(context.HttpContext.Request.Method, HttpMethod.Get.Method, StringComparison.OrdinalIgnoreCase) ? TransactionScopeOption.Required : TransactionScopeOption.Suppress;
            }

            return options;
        }

        private async Task RollbackAsync(ActionExecutingContext context, IUnitOfWorkManager unitOfWorkManager)
        {
            var currentUow = unitOfWorkManager.Current;
            if (currentUow != null)
            {
                await currentUow.RollbackAsync(context.HttpContext.RequestAborted);
            }
        }

        private static bool Succeed(ActionExecutedContext result)
        {
            return result.Exception == null || result.ExceptionHandled;
        }

    }
}
